/**
 * Copyright (C) 2025 pony working team
 * SPDX-License-Identifier: MulanPSL-2.0
 */

/* define to prevent recursive inclusion -------------------------------------*/
#ifndef __HAL_UART_H__
#define __HAL_UART_H__

/* includes (standard library, system) ---------------------------------------*/
#include <stdint.h>
#include <stddef.h>
#include <stdarg.h>
/* includes (other library) --------------------------------------------------*/
/* includes (project) --------------------------------------------------------*/
#include <x_list.h>
#include <x_module.h>
#include <x_ring.h>
/* includes (local) ----------------------------------------------------------*/
#include "hal.h"

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

/* defines -------------------------------------------------------------------*/

#define HAL_UART_RING_SIZE 256

#define HAL_UART_MODE_POLL (1 << 0)
#define HAL_UART_MODE_INT  (1 << 1)

#define ERRNO_HAL_UART_ILLEGAL_ID        ERRNO_JOIN(MID_HAL, 0x21)
#define ERRNO_HAL_UART_ILLEGAL_BUFF      ERRNO_JOIN(MID_HAL, 0x22)
#define ERRNO_HAL_UART_ILLEGAL_OPERATION ERRNO_JOIN(MID_HAL, 0x23)
#define ERRNO_HAL_UART_ILLEGAL_NAME      ERRNO_JOIN(MID_HAL, 0x24)
#define ERRNO_HAL_UART_NO_MATCH          ERRNO_JOIN(MID_HAL, 0x25)

/* typedefs ------------------------------------------------------------------*/

typedef struct hal_uart hal_uart_t;

typedef struct hal_uart_methods {
    int (*ioctl)(hal_uart_t *, int, va_list);
    int (*poll_getc)(hal_uart_t *);
    int (*timed_getc)(hal_uart_t *, size_t timeout);
    size_t (*poll_putc)(hal_uart_t *, unsigned char);
    int (*tx_start)(hal_uart_t *);
} hal_uart_methods_t;

struct hal_uart {
    hal_dev_t parent;
    uint8_t mode;

    ring_t *rxring;
    ring_t *txring;

    k_sem_t rxsem;
    k_sem_t txsem;
    k_mutex_t rxmux;
    k_mutex_t txmux;

    const hal_uart_methods_t *methods;
};

/* macro ---------------------------------------------------------------------*/
/* inlines -------------------------------------------------------------------*/
/* externs -------------------------------------------------------------------*/

extern hal_uart_t *hal_uart_open(const char *name);
extern size_t hal_uart_poll_read(hal_uart_t *uart, unsigned char *buf, size_t len);
extern int hal_uart_getc(hal_uart_t *uart);
extern int hal_uart_poll_getc(hal_uart_t *uart);
extern int hal_uart_timed_getc(hal_uart_t *uart, size_t timeout);
extern size_t hal_uart_read(hal_uart_t *uart, unsigned char *buf, size_t len);
extern size_t hal_uart_poll_write(hal_uart_t *uart, const unsigned char *buf, size_t len);
extern size_t hal_uart_putc(hal_uart_t *uart, const unsigned char ch);
extern size_t hal_uart_poll_putc(hal_uart_t *uart, const unsigned char ch);
extern size_t hal_uart_write(hal_uart_t *uart, const unsigned char *buf, size_t len);
extern void hal_rx_putc(hal_uart_t *uart, unsigned char ch);
extern size_t hal_tx_getc(hal_uart_t *uart, unsigned char *ch);
extern int hal_uart_register(hal_uart_t *uart, const char *name, const hal_uart_methods_t *methods,
                             uintptr_t data);

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif /* __HAL_UART_H__ */
